package com.psychologyCommunity.Community.service;


import com.psychologyCommunity.Community.dao.elasticSearch.DiscussPostRepository;
import com.psychologyCommunity.Community.entity.DiscussPost;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class ElasticsearchService {

    @Autowired
    private DiscussPostRepository discussPostRepository;
    @Autowired
    private ElasticsearchService elasticsearchRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchRestTemplate;

    //    首先需要提供一个方法 ，能够向es服务器里提交，新产生的帖子，这个方法 不要返回值
    public void saveDiscussPost(DiscussPost discussPost) {
        discussPostRepository.save(discussPost);
    }

    //删除帖子（根据帖子id来删除）
    public void deleteDiscussPost(int id) {
        discussPostRepository.deleteById(id);
    }

    //    搜索方法 搜索之后 返回一个Page类型的数据，里面封装了多条帖子
//    搜索帖子时 要传入搜索的关键字 keyword，搜索支持分页，要传入当前是第几页current，以及每页显示多少条数据limit
    public Page<DiscussPost> searchDiscuss(String keyword, int current, int limit) {
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content"))
                .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("core").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withPageable(PageRequest.of(current, limit))
                .withHighlightFields(
                        //表示 如果 在某字段中拿到了关键词 前后加什么标签，可以自己进行设置
                        new HighlightBuilder.Field("title").preTags("<em>").postTags("<em>")
                        , new HighlightBuilder.Field("content").preTags("<em>").postTags("<em>")

                ).build();
        //返回的最终的数据 --queryForPage会得到结果，然后这个SearchResultMapper拿到参数response会自动处理得到的结果
            return elasticsearchRestTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                //通过response 得到多个hits(命中的数据) ，hits中封装了多条数据
                SearchHits hits = response.getHits();
                if (hits.getTotalHits() <= 0) {
                    return null;
                }
                //实例化一个帖子的集合，并在其中实例化了一个帖子实例，根据命中的数据重新去构造帖子并放在集合中
                List<DiscussPost> list = new ArrayList<>();
                for (SearchHit hit : hits) {//遍历这个命中的数据
                    DiscussPost post = new DiscussPost();
                    String id = hit.getSourceAsMap().get("id").toString();//得到hits中的每条数据的--先得到字符串id 存的时候再转一下
                    post.setId(Integer.valueOf(id));
                    String userId = hit.getSourceAsMap().get("userid").toString();//得到hits中的每条数据的--先得到字符串id 存的时候再转一下
                    post.setUser_id(Integer.valueOf(userId));
                    String title = hit.getSourceAsMap().get("title").toString();
                    post.setTitle(title);
                    String content = hit.getSourceAsMap().get("content").toString();
                    post.setContent(content);
                    String status = hit.getSourceAsMap().get("status").toString();
                    post.setTitle(status);
                    String createTime = hit.getSourceAsMap().get("createTime").toString();
                    post.setCreateTime(new Date(Long.valueOf(createTime)));
                    String commentCount = hit.getSourceAsMap().get("commentCount").toString();//得到hits中的每条数据的--先得到字符串id 存的时候再转一下
                    post.setId(Integer.valueOf(commentCount));

                    //处理高亮显示的结果//先获得高亮显示的结果
                    HighlightField titleField = hit.getHighlightFields().get("title");
                    if (titleField != null) {
                        post.setTitle(titleField.getFragments()[0].toString());//因为可能会匹配上多个 高亮词，拿第一个 转成字符串set就行了
                    }
                    HighlightField contentField = hit.getHighlightFields().get("content");
                    if (contentField != null) {
                        post.setContent(contentField.getFragments()[0].toString());//因为可能会匹配上多个 高亮词，拿第一个 转成字符串set就行了
                    }
                    list.add(post);
                }
                return new AggregatedPageImpl(list, pageable, hits.getTotalHits()
                        , response.getAggregations(), response.getScrollId(), hits.getMaxScore());
            }
        });
//        //构造完之后 按照上面构建的搜索条件 来进行查询
//        System.out.println(page.getTotalElements());//查询一共有多少条数据匹配
//        System.out.println(page.getTotalPages());//按照当前的分页条件，一共有多少页
//        System.out.println(page.getNumber());//当前处于第几页
//        System.out.println(page.getSize());//每一页最多显示多少数据
//        //循环遍历
//        for (DiscussPost post : page) {
//            //每次遍历的post打印出来
//            System.out.println(post);
//        }


    }
}
